<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>drawRectangle(已接入lve.js)</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .container{
      width: 1000px;
      height: 700px;
      margin: 10% auto;
    }
    .control{
      margin-bottom: 10px;
    }
    #out-box{
      width: 100%;
      height: 600px;
      border: 2px solid #000;
      position: relative;
      overflow: hidden;
    }
    .rect{
      position: absolute;
      /* box-shadow: 0 0 0 1999px rgba(0, 0, 0, .4); */
      left: -9999px;
      top: 0;
      width: 0;
      height: 0;
      border: 2px solid;
      cursor: move;
    }
    .circle{
      position: absolute;
      /* box-shadow: 0 0 0 1999px rgba(0, 0, 0, .4); */
      left: -9999px;
      top: 0;
      width: 0;
      height: 0;
      border: 2px solid;
      border-radius: 50%;
      cursor: move;
    }
    .rect>span, .circle>span{
      position: absolute;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      border: 2px solid;
      border-color: inherit;
      background-color: #fff;
    }
    .rect .left-top{
      left: -6px;
      top: -6px;
      cursor: nwse-resize;
    }
    .rect .middle-top{
      left: 50%;
      top: -6px;
      transform: translateX(-50%);
      cursor: n-resize;
    }
    .rect .right-top{
      right: -6px;
      top: -6px;
      cursor: nesw-resize;
    }
    .rect .right-middle{
      right: -6px;
      top: 50%;
      transform: translateY(-50%);
      cursor: e-resize;
    }
    .rect .right-bottom{
      right: -6px;
      bottom: -6px;
      cursor: nwse-resize;
    }
    .rect .middle-bottom{
      left: 50%;
      bottom: -6px;
      transform: translateX(-50%);
      cursor: s-resize;
    }
    .rect .left-bottom{
      left: -6px;
      bottom: -6px;
      cursor: nesw-resize;
    }
    .rect .left-middle{
      left: -6px;
      top: 50%;
      transform: translateY(-50%);
      cursor: w-resize;
    }
    .middle-middle{
      left: 50%;
      top: 50%;
      z-index: -1;
      transform: translate(-50%, -50%);
    }
  </style>
</head>
<body>
  <div id="root">
    <div class="container">
      <div class="control">
        <button @click="clear">清屏</button>
        <button @click="drawRect">绘制矩形</button>
        <button @click="drawCircle">绘制圆形</button>
        <input id="color-select" type="color" :value="defaultColor" @change="colorChange">
        <div class="list">
          <div :for="item in arr">{{item}}</div>
        </div>
      </div>
      <div id="out-box">
        <div id="rect" class="rect">
          <span class="left-top dot"></span>
          <span class="middle-top dot"></span>
          <span class="right-top dot"></span>
          <span class="right-middle dot"></span>
          <span class="right-bottom dot"></span>
          <span class="middle-bottom dot"></span>
          <span class="left-bottom dot"></span>
          <span class="left-middle dot"></span>
        </div>
        <div id="circle" class="circle">
          <span class="dot middle-middle"></span>
        </div>
      </div>
    </div>
  </div>
  <script type="module">
    import {Component} from '../core/index.js'
    const component = new Component({
        data() {
          return {
            time: {
              count: 0
            },
            defaultColor: '#f6b73c', // 默认画笔颜色
            dom: null, // 画布
            rect: null, // 矩形
            circle: null, // 圆形
            origin: null,
            arr: [1,2],
            parentBorder: 1, // 父元素边框 如果你明确知道边框宽度，就不需要Number(getComputedStyle(dom, null).borderWidth.split('px')[0])这行，直接赋值就行
            childBorder: 1 // 子元素边框 如果你明确知道边框宽度，就不需要Number(getComputedStyle(rect, null).borderWidth.split('px')[0])这行，直接赋值就行
          };
        },
        computed: {
        },
        watch: {
          time(val) {
            // console.log(val + 'change');
          },
          show(val) {
            console.log(val, 'display');
          }
        },
        created() {
        },
        mounted() {
          this.init()
        },
        destroyed() {
          this.dom = null
          this.rect = null
          this.origin = null
        },
        methods: {
          /**
           * 边框颜色控制
           */ 
          colorChange(e) {
            this.rect.style.borderColor = this.circle.style.borderColor = e.target.value
          },
          /**
           * 画笔颜色初始化
           */ 
          initColor() {
            this.rect.style.borderColor = this.circle.style.borderColor = document.getElementById('color-select').value
          },
          init() {
            this.dom = document.getElementById('out-box')
            this.rect  = document.getElementById('rect')
            this.circle = document.getElementById('circle')
            this.origin = this.dom.getBoundingClientRect()
            this.parentBorder = Number(getComputedStyle(this.dom, null).borderWidth.split('px')[0])
            this.childBorder = Number(getComputedStyle(this.rect, null).borderWidth.split('px')[0])
            this.initColor()
          },
          /**
           * 开始绘制圆形
           */
          drawCircle() {
            this.dom.style.cursor = 'crosshair'
            let centerX = null
            let centerY = null
            this.dom.onmousedown = e => {
              if (e.target !== this.dom) return
              centerX = e.offsetX
              centerY = e.offsetY
              this.circle.style.left = centerX + 'px'
              this.circle.style.top = centerY + 'px'
              this.dom.onmousemove = e => {
                const width = e.clientX - this.origin.x - centerX
                const height = e.clientY - this.origin.y - centerY
                const radius = Math.max(Math.abs(width), Math.abs(height))
                this.circle.style.width = this.circle.style.height = radius * 2 + 'px'
              }
              this.dom.onmouseup = e => {
                this.dom.onmousedown = null
                this.dom.onmousemove = null
                this.dom.onmouseup = null
                this.dom.style.cursor = ''
                this.editCircle()
              }
            }
          },
          /**
           * 开始绘制矩形
          */
          drawRect() {
            this.dom.style.cursor = 'crosshair'
            this.dom.onmousedown = e => {
              if (e.target !== this.dom) return
              const left = e.offsetX
              const top = e.offsetY
              this.rect.style.left = left + 'px'
              this.rect.style.top = top + 'px'
              this.dom.onmousemove = e => {
                // 宽高边界限制
                const widthArea = e.clientX - this.origin.x > this.dom.offsetWidth - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetWidth - (this.parentBorder * 2 + this.childBorder * 2) : e.clientX - this.origin.x
                const heightArea = e.clientY - this.origin.y > this.dom.offsetHeight - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetHeight - (this.parentBorder * 2 + this.childBorder * 2) : e.clientY - this.origin.y
                this.rect.style.width = widthArea - left + 'px'
                this.rect.style.height = heightArea - top + 'px'
              }
              this.dom.onmouseup = e => {
                this.dom.onmousedown = null
                this.dom.onmousemove = null
                this.dom.onmouseup = null
                this.dom.style.cursor = ''
                this.editRect()
              }
            }
          },
          editCircle() {
            this.circle.onmousedown = e => {
              if (e.target !== this.circle) return
              this.rect.style.zIndex = 0
              this.circle.style.zIndex = 1
              const flag = this.mousedownHandle(e, this.circle)
              const [dragX, dragY] = flag
              let left = e.clientX
              let top = e.clientY
              // 拖动
              if (dragX === -1 && dragY === -1) {
                left -= this.circle.offsetLeft // 要保持之前矩形框的坐标值
                top -= this.circle.offsetTop
              }
              const child = e.target.getBoundingClientRect()
              const dom = this.dom.getBoundingClientRect()
              document.onmousemove = e => {
                // 取消浏览器因回流导致的默认事件及冒泡事件
                e.preventDefault()
                if (e.stopPropagation) {
                  e.stopPropagation()
                } else {
                  e.cancelable = true
                }
                const finallPoint = {
                  left: 0,
                  top: 0,
                  width: 0,
                  height: 0
                }
                if (dragX === -1 && dragY === -1) {
                  this.circle.style.cursor = 'move'
                  const rightArea = this.dom.offsetWidth - this.circle.offsetWidth - (this.childBorder * 2) // 右边界
                  const bottomArea = this.dom.offsetHeight - this.circle.offsetHeight - (this.childBorder * 2) // 下边界
                  const leftArea = 0 // 左边界
                  const topArea = 0 // 上边界
                  finallPoint.left = e.clientX - left > rightArea ? rightArea : (e.clientX - left< leftArea ? leftArea : e.clientX - left)
                  finallPoint.top = e.clientY - top > bottomArea ? bottomArea : (e.clientY - top < topArea ? topArea : e.clientY - top)
                  this.circle.style.left = finallPoint.left + 'px'
                  this.circle.style.top = finallPoint.top + 'px'
                }
              }
              document.onmouseup = e => {
                document.onmousemove = null
                document.onmouseup = null
                this.circle.style.cursor = 'move'
              }
            }
          },
          editRect() {
            this.rect.onmousedown = e => {
              if (e.target !== this.rect && e.target.className.indexOf('dot') === -1) return // 类名中包含被放行的dot除外
              this.rect.style.zIndex = 1
              this.circle.style.zIndex = 0
              const flag = this.mousedownHandle(e, this.rect)
              let left = e.clientX
              let top = e.clientY
              const width = rect.offsetWidth
              const height = rect.offsetHeight
              const [dragX, dragY] = flag
              if (dragX === 1 && dragY === 1) {
                dragX = -1
                dragY = -1
              }
              // 拖动
              if (dragX === -1 && dragY === -1) {
                left -= this.rect.offsetLeft // 要保持之前矩形框的坐标值
                top -= this.rect.offsetTop
              }
              const child = e.target.getBoundingClientRect()
              const dom = this.dom.getBoundingClientRect()
              document.onmousemove = e => {
                // 取消浏览器因回流导致的默认事件及冒泡事件
                e.preventDefault()
                if (e.stopPropagation) {
                  e.stopPropagation()
                } else {
                  e.cancelable = true
                }
                const finallPoint = {
                  left: 0,
                  top: 0,
                  width: 0,
                  height: 0
                }
                if (dragX === -1 && dragY === -1) {
                  this.rect.style.cursor = 'move'
                  const rightArea = this.dom.offsetWidth - this.rect.offsetWidth - (this.childBorder * 2) // 右边界
                  const bottomArea = this.dom.offsetHeight - this.rect.offsetHeight - (this.childBorder * 2) // 下边界
                  const leftArea = 0 // 左边界
                  const topArea = 0 // 上边界
                  finallPoint.left = e.clientX - left > rightArea ? rightArea : (e.clientX - left< leftArea ? leftArea : e.clientX - left)
                  finallPoint.top = e.clientY - top > bottomArea ? bottomArea : (e.clientY - top < topArea ? topArea : e.clientY - top)
                  this.rect.style.left = finallPoint.left + 'px'
                  this.rect.style.top = finallPoint.top + 'px'
                } else if (dragX === 0 && dragY === 0) { // 左上角拉伸
                  finallPoint.left = e.clientX > dom.x ? ((e.clientX > (left + width)) ? left + width - dom.x : e.clientX - dom.x) : 0
                  finallPoint.top = e.clientY > dom.y ? ((e.clientY > (top + height)) ? top + height - dom.y : e.clientY - dom.y) : 0
                  finallPoint.width = e.clientX > dom.x ? ((e.clientX > (left + width)) ? 0 : width + (left - e.clientX)) : width + (left - dom.x)
                  finallPoint.height = e.clientY > dom.y ? ((e.clientY > (top + height)) ? 0 : height + (top - e.clientY)) : height + (top - dom.y)
                  this.rect.style.left = finallPoint.left + 'px'
                  this.rect.style.top = finallPoint.top + 'px'
                  this.rect.style.width = finallPoint.width + 'px'
                  this.rect.style.height = finallPoint.height + 'px'
                } else if (dragX === 1 && dragY === 0) { // 中上拉伸
                  finallPoint.top = e.clientY > dom.y ? ((e.clientY > (top + height)) ? top + height - dom.y : e.clientY - dom.y) : 0
                  finallPoint.height = e.clientY > dom.y ? ((e.clientY > (top + height)) ? 0 : height + (top - e.clientY)) : height + (top - dom.y)
                  this.rect.style.top = finallPoint.top + 'px'
                  this.rect.style.height = finallPoint.height + 'px'
                } else if (dragX === 2 && dragY === 0) { // 右上角拉伸
                  finallPoint.top = e.clientY > dom.y ? ((e.clientY > (top + height)) ? top + height - dom.y : e.clientY - dom.y) : 0
                  finallPoint.width = (e.clientX - left + width > this.dom.offsetWidth - this.rect.offsetLeft - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetWidth - this.rect.offsetLeft - (this.parentBorder * 2 + this.childBorder * 2) : e.clientX - left + width)
                  finallPoint.height = e.clientY > dom.y ? ((e.clientY > (top + height)) ? 0 : height + (top - e.clientY)) : height + (top - dom.y)
                  this.rect.style.top = finallPoint.top + 'px'
                  this.rect.style.width = finallPoint.width + 'px'
                  this.rect.style.height = finallPoint.height + 'px'
                } else if (dragX === 2 && dragY === 1) { // 右中拉伸
                  finallPoint.width = (e.clientX - left + width > this.dom.offsetWidth - this.rect.offsetLeft - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetWidth - this.rect.offsetLeft - (this.parentBorder * 2 + this.childBorder * 2) : e.clientX - left + width)
                  this.rect.style.width = finallPoint.width + 'px'
                }else if (dragX === 2 && dragY === 2) { // 右下角拉伸
                  finallPoint.width = (e.clientX - left + width > this.dom.offsetWidth - this.rect.offsetLeft - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetWidth - this.rect.offsetLeft - (this.parentBorder * 2 + this.childBorder * 2) : e.clientX - left + width)
                  finallPoint.height = (e.clientY- top + height > this.dom.offsetHeight - this.rect.offsetTop - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetHeight - this.rect.offsetTop - (this.parentBorder * 2 + this.childBorder * 2) : e.clientY- top + height)
                  this.rect.style.width = finallPoint.width + 'px'
                  this.rect.style.height = finallPoint.height + 'px'
                } else if (dragX === 1 && dragY === 2) { // 中下拉伸
                  finallPoint.height = (e.clientY- top + height > this.dom.offsetHeight - this.rect.offsetTop - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetHeight - this.rect.offsetTop - (this.parentBorder * 2 + this.childBorder * 2) : e.clientY- top + height)
                  this.rect.style.height = finallPoint.height + 'px'
                } else if (dragX === 0 && dragY === 2) { // 左下角拉伸
                  finallPoint.left = e.clientX > dom.x ? ((e.clientX > (left + width)) ? left + width - dom.x : e.clientX - dom.x) : 0
                  finallPoint.width = e.clientX > dom.x ? ((e.clientX > (left + width)) ? 0 : width + (left - e.clientX)) : width + (left - dom.x)
                  finallPoint.height = (e.clientY- top + height > this.dom.offsetHeight - this.rect.offsetTop - (this.parentBorder * 2 + this.childBorder * 2) ? this.dom.offsetHeight - this.rect.offsetTop - (this.parentBorder * 2 + this.childBorder * 2) : e.clientY- top + height)
                  this.rect.style.left = finallPoint.left + 'px'
                  this.rect.style.width = finallPoint.width + 'px'
                  this.rect.style.height = finallPoint.height + 'px'
                } else if (dragX === 0 && dragY === 1) { // 左中拉伸
                  finallPoint.left = e.clientX > dom.x ? ((e.clientX > (left + width)) ? left + width - dom.x : e.clientX - dom.x) : 0
                  finallPoint.width = e.clientX > dom.x ? ((e.clientX > (left + width)) ? 0 : width + (left - e.clientX)) : width + (left - dom.x)
                  this.rect.style.left = finallPoint.left + 'px'
                  this.rect.style.width = finallPoint.width + 'px'
                }
              }
              document.onmouseup = e => {
                document.onmousemove = null
                document.onmouseup = null
                this.rect.style.cursor = 'move'
              }
            }
          },
          /**
           * mousedown逻辑处理
           */
          mousedownHandle(e, target) {
            let flag = 0 // 点击的是除边角以外的其他部分 拖动
            let startX = e.offsetX
            let startY = e.offsetY
            let width = e.target.offsetWidth
            let height = e.target.offsetHeight
            if (e.target !== target) {
              flag = 1 // 点击的是边角 缩放
              const parent = e.target.offsetParent.getBoundingClientRect()
              const child = e.target.getBoundingClientRect()
              startX = child.x - parent.x
              startY = child.y - parent.y
              width = e.target.offsetParent.offsetWidth
              height = e.target.offsetParent.offsetHeight
            }
            const difference = 12 // 点击四边角12 px范围为拉伸，其他为拖动,这个值可以根据你需要的来调整
            let left = 0 // 0 => left, 1 => middle, 2 => right, -1 => 点击的位置不能被拖动
            let top = 0 // 0 => top, 1 => middle, 2 => bottom, -1 => 点击的位置不能被拖动
            if (startX < difference) { // 点击的位置为矩形左侧
              left = 0
            } else if (startX > width / 2 - difference && startX < width / 2 + difference) { // 点击的位置为矩形中间 width/2 - 6px ~ width/2 + 6px
              left = 1
            } else if (startX < width && startX > width - difference){ // 点击的位置为矩形右侧 width - 6px ~ width
              left = 2
            } else {
              left = -1
            }

            if (startY < difference) { // 点击的位置为矩形上侧
              top = 0
            } else if (startY > height / 2 - difference && startY < height / 2 + difference) { // 点击的位置为矩形中间 height/2 - 6px ~ height/2 + 6px
              top = 1
            } else if (startY < height && startY > height - difference){ // 点击的位置为矩形下侧 height - 6px ~ height
              top = 2
            } else {
              top = -1
            }
            if (left === -1 || top === -1) {
              return [-1, -1]
            }
            return [left, top] // 只会有八个位置能被准确返回，其余都是返回[-1, -1]
          },
          clear() {
            if (this.rect) {
              this.rect.style.left = '-9999px'
              this.rect.style.top = 0
              this.rect.style.width = 0
              this.rect.style.height = 0
            }
            if (this.circle) {
              this.circle.style.left = '-9999px'
              this.circle.style.top = 0
              this.circle.style.width = 0
              this.circle.style.height = 0
            }
          }
        }
    });
    component.mount('#root')
  </script>
</body>
</html>